package com.SPOooON.googletaskssync;

import java.util.ArrayList;
import java.util.HashMap;

import com.google.api.client.util.DateTime;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.provider.BaseColumns;
import android.util.Log;

public class GoogleTasksContentProvider extends ContentProvider {	
	
	private static final String TAG = "GoogleTasksContentProvider";
	
	private GoogleTasksDatabaseHelper dbHelper;
	
	@Override
	public boolean onCreate() {
		dbHelper = new GoogleTasksDatabaseHelper(getContext());
		return true;
	}
	
	@Override
	public String getType(Uri uri) {
		// TODO Auto-generated method stub
		return null;
	}
	@Override
	public Cursor query(Uri uri
			, String[] projection
			, String selection
			, String[] selectionArgs
			, String sortOrder) {
		
		SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
		
		switch(URI_MATCHER.match(uri)) {
		
		case Tasks.TOKEN:{
			qb.setTables(Tasks.TABLE_NAME);
			qb.setProjectionMap(Tasks.PROJECTIONMAP);
			
			if (sortOrder==null) {
				sortOrder = Tasks.Columns.ACCOUNT
				+ " , " + Tasks.Columns.TASKLIST
				+ " , " + Tasks.Columns.POSITION
				+ " , " + Tasks.Columns._ID;
			}
			break;
		}
		
		case TaskLists.TOKEN:{
			qb.setTables(TaskLists.TABLE_NAME);
			qb.setProjectionMap(TaskLists.PROJECTIONMAP);
			break;
		}
		
		case Accounts.TOKEN:{
			qb.setTables(Accounts.TABLE_NAME);
			qb.setProjectionMap(Accounts.PROJECTIONMAP);
			break;
		}
		
		default:
			throw new IllegalArgumentException("URI " + uri + " not supported");
		}
		SQLiteDatabase db = dbHelper.getWritableDatabase();
		
		Cursor cursor = qb.query(db, projection, selection, selectionArgs, null, null, sortOrder);
		cursor.setNotificationUri(getContext().getContentResolver(), uri);
		
		return cursor;
	}
	

	@Override
	public Uri insert(Uri uri, ContentValues values) {
		
		SQLiteDatabase db = dbHelper.getWritableDatabase();
		
		switch(URI_MATCHER.match(uri)) {
		
			case Tasks.TOKEN:{
				long id = db.insert(Tasks.TABLE_NAME, Tasks.Columns.ID, values);
				getContext().getContentResolver().notifyChange(uri, null);
				return Tasks.CONTENT_URI.buildUpon().appendPath(String.valueOf(id)).build();
			}
		
			case TaskLists.TOKEN:{
				long id = db.insert(TaskLists.TABLE_NAME, Tasks.Columns.ID, values);
				getContext().getContentResolver().notifyChange(uri, null);
				return TaskLists.CONTENT_URI.buildUpon().appendPath(String.valueOf(id)).build();
			}
		
			default: throw new UnsupportedOperationException("URI " + uri.toString() + " not supported");
		}
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
		
		SQLiteDatabase db = dbHelper.getWritableDatabase();
		
		switch(URI_MATCHER.match(uri)) {
		
		case Tasks.TOKEN:{
			
			//Log.d(TAG, values.toString());
			
			int rows = db.update(Tasks.TABLE_NAME, values, selection, selectionArgs);			
			getContext().getContentResolver().notifyChange(uri, null);
			return rows;
		}
	
		case TaskLists.TOKEN:{
			int rows = db.update(TaskLists.TABLE_NAME, values, selection, selectionArgs);
			getContext().getContentResolver().notifyChange(uri, null);
			return rows;
		}
	
		default: throw new UnsupportedOperationException("URI " + uri.toString() + " not supported");
		}		
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		SQLiteDatabase db = dbHelper.getWritableDatabase();
		
		switch(URI_MATCHER.match(uri)) {
		
		case Tasks.TOKEN:{
			int rows = db.delete(Tasks.TABLE_NAME, selection, selectionArgs);
			getContext().getContentResolver().notifyChange(uri, null);
			return rows;
		}
	
		case TaskLists.TOKEN:{
			int rows = db.delete(TaskLists.TABLE_NAME, selection, selectionArgs);
			getContext().getContentResolver().notifyChange(uri, null);
			return rows;
		}
	
		default: throw new UnsupportedOperationException("URI " + uri.toString() + " not supported");
		}		
	}

	public class GoogleTasksDatabaseHelper extends SQLiteOpenHelper {
		
		private static final String DATABASE_NAME = "googletasks.db";
		private static final int DATABASE_VERSION = 11;

		public GoogleTasksDatabaseHelper(Context context) {
			super(context, DATABASE_NAME, null, DATABASE_VERSION);
		}
		
		@Override
		public void onCreate(SQLiteDatabase db) {
			db.execSQL("CREATE TABLE " + Tasks.TABLE_NAME + " ( "
						+ Tasks.Columns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
						+ Tasks.Columns.ID + " TEXT, "
						+ Tasks.Columns.ETAG + " TEXT, "
						+ Tasks.Columns.TITLE + " TEXT, "
						+ Tasks.Columns.UPDATED + " UNSIGNED BIGINT, "
						+ Tasks.Columns.SELFLINK + " TEXT, "
						+ Tasks.Columns.PARENT + " TEXT, "
						+ Tasks.Columns.POSITION + " TEXT, "
						+ Tasks.Columns.NOTES + " TEXT, "
						+ Tasks.Columns.STATUS + " TEXT, "
						+ Tasks.Columns.DUE + " UNSIGNED BIGINT, "
						+ Tasks.Columns.COMPLETED + " UNSIGNED BIGINT, "
						+ Tasks.Columns.DELETED + " BOOLEAN, "
						+ Tasks.Columns.HIDDEN + " BOOLEAN, "
						
						+ Tasks.Columns.TASKLIST + " INT, "
						+ Tasks.Columns.NEW + " BOOLEAN, "
						+ Tasks.Columns.ACCOUNT + " TEXT, "
						+ Tasks.Columns.PREVIOUS + " INTEGER, "
						
						+ "UNIQUE (" + Tasks.Columns._ID + ") ON CONFLICT REPLACE " 
						+ " ) " );
			
			db.execSQL("CREATE TABLE " + TaskLists.TABLE_NAME + " ( "
					+ TaskLists.Columns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
					+ TaskLists.Columns.ID + " TEXT, "
					+ TaskLists.Columns.ETAG + " TEXT, "
					+ TaskLists.Columns.TITLE + " TEXT, "
					+ TaskLists.Columns.SELFLINK + " TEXT, "
					+ TaskLists.Columns.UPDATED + " UNSIGNED BIGINT, "
					
					+ TaskLists.Columns.NEW + " BOOLEAN, "
					+ TaskLists.Columns.ACCOUNT + " TEXT, "
					
					+ "UNIQUE (" + TaskLists.Columns._ID + ") ON CONFLICT REPLACE " 
					+ " ) ");
			
			db.execSQL("CREATE VIEW " + Accounts.TABLE_NAME + " AS SELECT "
					+ "MAX( " + Accounts.Columns._ID + " ) AS _ID, "
					+ Accounts.Columns.ACCOUNT 
					+ " FROM " + TaskLists.TABLE_NAME
					+ " GROUP BY " + Accounts.Columns.ACCOUNT
					);
		}

		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
			Log.d("GoogleTasksContentProvider.GoogleTasksDatabaseHelper", "updating database");
			db.execSQL("DROP TABLE IF EXISTS " + TaskLists.TABLE_NAME);
			db.execSQL("DROP TABLE IF EXISTS " + Tasks.TABLE_NAME);
			db.execSQL("DROP VIEW IF EXISTS " + Accounts.TABLE_NAME);
			onCreate(db);
		}
	}
	
	public static final String AUTHORITY = "com.SPOooON.googletaskssync";
	private static final Uri BASE_URI = Uri.parse("content://" + AUTHORITY);
	public static final UriMatcher URI_MATCHER = buildUriMatcher();
	
	private static  UriMatcher buildUriMatcher() {
        final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
        final String authority = AUTHORITY;

        matcher.addURI(authority, Tasks.TABLE_NAME, Tasks.TOKEN);
        matcher.addURI(authority, TaskLists.TABLE_NAME, TaskLists.TOKEN);
        matcher.addURI(authority, Accounts.TABLE_NAME, Accounts.TOKEN);

        return matcher;
	}
	
	public static DateTime getTimeStamp(){
		return new DateTime(System.currentTimeMillis(), 0);
	}

	public static class Tasks {
		
		public static final String TABLE_NAME = "tasks";			
		public static final Uri CONTENT_URI = BASE_URI.buildUpon().appendPath(TABLE_NAME).build();
		public static final int TOKEN = 1;
		
		public static final HashMap<String, String> PROJECTIONMAP = new HashMap<String, String>();		
		
		static {
			PROJECTIONMAP.put(Columns.ID, Columns.ID);
			PROJECTIONMAP.put(Columns.ETAG, Columns.ETAG);
			PROJECTIONMAP.put(Columns.TITLE, Columns.TITLE);
			PROJECTIONMAP.put(Columns.UPDATED, Columns.UPDATED);
			PROJECTIONMAP.put(Columns.SELFLINK, Columns.SELFLINK);
			PROJECTIONMAP.put(Columns.PARENT, Columns.PARENT);
			PROJECTIONMAP.put(Columns.POSITION, Columns.POSITION);
			PROJECTIONMAP.put(Columns.NOTES, Columns.NOTES);
			PROJECTIONMAP.put(Columns.STATUS, Columns.STATUS);
			PROJECTIONMAP.put(Columns.DUE, Columns.DUE);
			PROJECTIONMAP.put(Columns.COMPLETED, Columns.COMPLETED);
			PROJECTIONMAP.put(Columns.DELETED, Columns.DELETED);
			PROJECTIONMAP.put(Columns.HIDDEN, Columns.HIDDEN);
			
			PROJECTIONMAP.put(Columns._ID, Columns._ID);
			PROJECTIONMAP.put(Columns.TASKLIST, Columns.TASKLIST);			
			PROJECTIONMAP.put(Columns.NEW, Columns.NEW);
			PROJECTIONMAP.put(Columns.ACCOUNT, Columns.ACCOUNT);
			PROJECTIONMAP.put(Columns.PREVIOUS, Columns.PREVIOUS);
		}
		
		private Tasks(){}
		
		public static class Columns implements BaseColumns {
			
			private Columns(){}
			
			public static final String ID = "googleid";
			public static final String ETAG = "etag";
			public static final String TITLE = "title";
			public static final String UPDATED = "updated";
			public static final String SELFLINK = "selfLink";
			public static final String PARENT = "parent";
			public static final String POSITION = "position";
			public static final String NOTES = "notes";
			public static final String STATUS = "status";
			public static final String DUE = "due";
			public static final String COMPLETED = "completed";
			public static final String DELETED = "deleted";
			public static final String HIDDEN = "hidden";
			
			public static final String TASKLIST = "tasklist";
			public static final String NEW = "new";
			public static final String ACCOUNT = "account";
			public static final String PREVIOUS = "previous";
		}
		
		public static class Status {
			public static final String NEEDSACTION = "needsAction";
			public static final String COMPLETED = "completed";
			
			public static boolean statusToBool(String status) {				
				if (status != null && status.equals(COMPLETED)) return true;
				return false;
			}
			
			public static String booleanToStatus(boolean status) {
				if (status) return COMPLETED;
				return NEEDSACTION;
			}
			
			public static String invert(String status) {
				if (status.equals(COMPLETED)) return NEEDSACTION;
				return COMPLETED;
			}
		}
	}
	
	public static class TaskLists {
		
		public static final String TABLE_NAME = "tasklists";			
		public static final Uri CONTENT_URI = BASE_URI.buildUpon().appendPath(TABLE_NAME).build();
		public static final int TOKEN = 2;
		
		public static final HashMap<String, String> PROJECTIONMAP = new HashMap<String, String>();		
		
		static {
			PROJECTIONMAP.put(Columns.ID, Columns.ID);
			PROJECTIONMAP.put(Columns.ETAG, Columns.ETAG);
			PROJECTIONMAP.put(Columns.TITLE, Columns.TITLE);
			PROJECTIONMAP.put(Columns.SELFLINK, Columns.SELFLINK);
			PROJECTIONMAP.put(Columns.UPDATED, Columns.UPDATED);
			
			PROJECTIONMAP.put(Columns._ID, Columns._ID);
			PROJECTIONMAP.put(Columns.NEW, Columns.NEW);
			PROJECTIONMAP.put(Columns.ACCOUNT, Columns.ACCOUNT);
		}
		
		private TaskLists(){}			
		
		public static class Columns implements BaseColumns {
			
			private Columns(){}
			
			public static final String ID = "googleid";
			public static final String ETAG = "etag";
			public static final String TITLE = "title";
			public static final String SELFLINK = "selfLink";
			public static final String UPDATED = "updated";
			
			public static final String NEW = "new";
			public static final String ACCOUNT = "account";
		}
	}
	
	public static class Accounts {
		public static final String TABLE_NAME = "accounts";
		public static final Uri CONTENT_URI = BASE_URI.buildUpon().appendPath(TABLE_NAME).build();
		public static final int TOKEN = 3;
		
		public static final HashMap<String, String> PROJECTIONMAP = new HashMap<String, String>();		
		
		static {
			PROJECTIONMAP.put(Columns.ACCOUNT, Columns.ACCOUNT);
			PROJECTIONMAP.put(Columns._ID, Columns._ID);
		}
		
		private Accounts(){}			
		
		public static class Columns implements BaseColumns {
			
			private Columns(){}
			
			public static final String ACCOUNT = "account";
			public static final String _ID = "_id";
		}
	}
}
